home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------
- #
- # NewsWatcher - Macintosh NNTP Client Application
- #
- # Written by Steven Falkenburg
- # ©1990 Apple Computer, Inc.
- #
- #-----------------------------------------------------------
- #
- # netstuff.c
- #
- # The netstuff code module contains several routines which
- # handle network specific tasks of the program. Among
- # these are user authentication, and high-level file xfer
- # calls.
- #
- #-----------------------------------------------------------*/
-
- #pragma segment netstuff
-
- #include "compat.h"
- #include <String.h>
- #include <StdIO.h>
-
- #ifdef PROTOS
- #include <Types.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <Files.h>
- #include <Memory.h>
- #include <Errors.h>
- #include <Events.h>
- #include <Fonts.h>
- #include <Packages.h>
- #include <Lists.h>
- #include <ToolUtils.h>
- #include <Strings.h>
- #endif
-
- #include "MacTCPCommonTypes.h"
- #include "AddressXLation.h"
- #include "TCPPB.h"
- #include "nntp.h"
- #include "netstuff.h"
- #include "miscstuff.h"
- #include "userint.h"
- #include "newsprocess.h"
- #include "TCPHi.h"
- #include "FTPLow.h"
- #include "NNTPLow.h"
- #include "SMTPLow.h"
-
- static char gPwStr[256]; /* the user's password */
- unsigned long gSMTPAddress; /* the ip address of the SMTP host */
-
- /* local protos */
-
- pascal Boolean PasswordFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit);
- pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr);
-
-
- /* ChangeServerAddress is called to get a new name/address for the news
- or main server. The new address will be stored in the prefs file.
- */
-
- void ChangeServerAddress(Boolean forNews)
- {
- DialogPtr theDlg;
- short iType;
- Handle iHndl;
- Rect iBox;
- Str255 serverName;
- short item;
- extern Boolean gDone;
- extern TPrefRec gPrefs;
-
- if (forNews) {
- if (gPrefs.newsServerName[0] == '\0') {
- SysBeep(1);
- BlockMove(kNNTPName,serverName,kNNTPNameLen);
- }
- else
- BlockMove(gPrefs.newsServerName,serverName,(gPrefs.newsServerName)[0]+1);
- theDlg = GetNewDialog(kNewsServerAddrID,nil,(WindowPtr)-1);
- }
- else {
- if (gPrefs.mailServerName[0] == '\0') {
- SysBeep(1);
- BlockMove(kSMTPName,serverName,kSMTPNameLen);
- }
- else
- BlockMove(gPrefs.mailServerName,serverName,(gPrefs.mailServerName)[0]+1);
- theDlg = GetNewDialog(kMailServerAddrID,nil,(WindowPtr)-1);
- }
-
- OutlineOK(theDlg);
- GetDItem(theDlg,3,&iType,&iHndl,&iBox);
- SetIText(iHndl,serverName);
- SelIText(theDlg,3,0L,32767L);
- do {
- ModalDialog(CmdKeyFilter,&item);
- } while (item!=okButton && item!=cancelButton);
- GetIText(iHndl,serverName);
- DisposDialog(theDlg);
-
- if (forNews) {
- if (item==okButton)
- BlockMove(serverName,gPrefs.newsServerName,serverName[0]+1);
- }
- else {
- if (item==okButton)
- BlockMove(serverName,gPrefs.mailServerName,serverName[0]+1);
- }
-
- if (!gDone && item==okButton) {
- ParamText("\pYou must quit and restart the program for this change to take effect.","\p","\p","\p");
- NoteAlert(kErrDlg,nil);
- }
- }
-
-
- /* GetConfiguration is called to get the news/mail server ip addresses,
- given their names from the preferences file.
- */
-
- void GetConfiguration(void)
- {
- extern unsigned long gNNTPAddress;
- extern TPrefRec gPrefs;
- Str255 name;
-
- if (gPrefs.newsServerName[0] == '\0' || gPrefs.mailServerName[0] == '\0') {
- ChangeServerAddress(true);
- if (gPrefs.newsServerName[0] == '\0') {
- gNNTPAddress = kNNTPAddress;
- return;
- }
- ChangeServerAddress(false);
- if (gPrefs.mailServerName[0] == '\0') {
- gSMTPAddress = kSMTPAddress;
- return;
- }
- }
- BlockMove(gPrefs.newsServerName,name,(gPrefs.newsServerName)[0]+1);
- p2cstr((char *)name);
- if (ConvertStringToAddr((char *)name,&gNNTPAddress)!=noErr)
- gNNTPAddress = kNNTPAddress;
- BlockMove(gPrefs.mailServerName,name,(gPrefs.mailServerName)[0]+1);
- p2cstr((char *)name);
- if (ConvertStringToAddr((char *)name,&gSMTPAddress)!=noErr)
- gSMTPAddress = kSMTPAddress;
- }
-
-
- /* This is the completion routine used for name-resolver calls.
- It sets the userDataPtr flag to indicate the call has completed.
- */
-
- pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr)
- {
- #pragma unused (hInfoPtr)
-
- *userDataPtr = 0xff;
- }
-
-
- /* ConvertStringToAddr is a simple call to get a host's IP number, given the name
- of the host.
- */
-
- OSErr ConvertStringToAddr(char *name,unsigned long *netNum)
- {
- struct hostInfo hInfo;
- OSErr result;
- char done = 0x00;
- extern Boolean gCancel;
-
- if ((result = OpenResolver(nil)) == noErr) {
- result = StrToAddr(name,&hInfo,DNRResultProc,&done);
- if (result == cacheFault)
- while (!done)
- ; /* wait for cache fault resolver to be called by interrupt */
- CloseResolver();
- if ((hInfo.rtnCode == noErr) || (hInfo.rtnCode == cacheFault)) {
- *netNum = hInfo.addr[0];
- strcpy(name,hInfo.cname);
- name[strlen(name)-1] = '\0';
- return noErr;
- }
- }
- *netNum = 0;
-
- return result;
- }
-
-
- /* PasswordFilter is the dialog filter used to switch all keys pressed
- into bullets (•) to hide the user's password from view.
- */
-
- pascal Boolean PasswordFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit)
- {
- DialogPeek dPeek;
- char theChar;
- short selStart,selEnd;
-
- dPeek = (DialogPeek) theDialog;
-
- if ((theEvent->what == keyDown) || (theEvent->what == autoKey)) {
- if ((theEvent->modifiers & cmdKey) != 0) {
- return CmdKeyFilter(theDialog,theEvent,itemHit);
- }
- if (dPeek->editField == 2) {
- theChar = theEvent->message & charCodeMask;
- selStart = (**(dPeek->textH)).selStart;
- selEnd = (**(dPeek->textH)).selEnd;
- switch (theChar) {
- case 0x08: /* backspace */
- if (selStart == selEnd) {
- if (selStart > 0)
- BlockMove((Ptr)gPwStr + selStart,(Ptr)gPwStr + selStart-1,strlen(gPwStr)-selStart+1);
- }
- else
- BlockMove((Ptr)gPwStr + selEnd,(Ptr)gPwStr + selStart,strlen(gPwStr)-selEnd+1);
- break;
- case CR: /* CR */
- case 0x03: /* enter */
- *itemHit = okButton;
- return true;
- break;
- case 0x09: /* tab */
- case 0x1c: /* left */
- case 0x1d: /* right */
- case 0x1e: /* up */
- case 0x1f: /* down */
- return false;
- break;
- default:
- BlockMove((Ptr)gPwStr+selEnd,(Ptr)gPwStr+selEnd+1,strlen(gPwStr)-selEnd+1);
- *(gPwStr+selStart) = theChar;
- theEvent->message = 0xffffff00 + '•';
- return false;
- break;
- }
- }
- if ((theChar == CR) || (theChar == 0x03)) {
- *itemHit = okButton;
- return true;
- }
- }
-
- return false;
- }
-
-
- /* GetUInfo displays modal dialogs for the user to enter their
- login id, host, and password for authentication.
- */
-
- Boolean GetUInfo(Str255 login,Str255 pass,Str255 host)
- {
- DialogPtr theDlg;
- short item,iType;
- Handle iHndl;
- Rect iRect;
-
- theDlg = GetNewDialog(kLoginDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- SetIText(iHndl,(StringPtr)c2pstr((char *)host));
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- SetIText(iHndl,(StringPtr)c2pstr((char *)login));
- do
- ModalDialog(CmdKeyFilter,&item);
- while (item != okButton && item != cancelButton);
-
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- GetIText(iHndl,host);
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- GetIText(iHndl,login);
-
- DisposDialog(theDlg);
-
- ParamText(host,"\p","\p","\p");
-
- p2cstr((char *)login);
- p2cstr((char *)host);
-
- if (item == cancelButton)
- return false;
-
- if (!host[0] || !login[0])
- return false;
-
- theDlg = GetNewDialog(kPassDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
-
- *gPwStr = '\0';
-
- do
- ModalDialog(PasswordFilter,&item);
- while (item != okButton && item != cancelButton);
-
- DisposDialog(theDlg);
- if (item == cancelButton)
- return false;
-
- strcpy(pass,gPwStr);
-
- return true;
- }
-
-
- /* Authenticate is called to check the accuracy of a user's id and
- password. Eventually, this procedure could be replaced with a
- more secure method. Currently, FTP is used for authentication.
- */
-
- Boolean Authenticate(void)
- {
- extern Boolean gAuthenticated;
- extern char gPass[];
- extern TPrefRec gPrefs;
- unsigned long connID;
-
- if (gAuthenticated)
- return true;
-
- if (!GetUInfo((StringPtr)gPrefs.name,(StringPtr)gPass,(StringPtr)gPrefs.host))
- return false;
-
- StatusWindow("Authenticating user...",-1);
-
- if (FTPConnect(&connID,(char *)gPrefs.host,(char *)gPrefs.name,gPass)!=noErr) {
- FTPDisconnect(connID);
- CloseStatusWindow();
- ParamText("\pIncorrect user information.","\p","\p","\p");
- NoteAlert(kErrDlg,nil);
- return false;
- }
- FTPDisconnect(connID);
- CloseStatusWindow();
-
- gAuthenticated = true;
- return true;
- }
-
-
- /* Logout removes the user's password from memory.
- */
-
- void Logout(void)
- {
- extern Boolean gAuthenticated;
- extern char gPass[];
-
- strcpy(gPass,"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
- gAuthenticated = false;
- }
-
-
- /* GetFromNet gets a newsrc file from the user's remote account.
- */
-
- void GetFromNet(void)
- {
- extern char gPass[];
- extern TPrefRec gPrefs;
-
- unsigned long connID;
- Ptr newsData;
- char *current;
- TwindowInfo *info;
- WindowPtr window;
- OSErr err;
- extern TPrefRec gPrefs;
-
- if (!Authenticate())
- return;
-
- StatusWindow("Establishing FTP Connection...",-1);
-
- if (FTPConnect(&connID,(char *)gPrefs.host,(char *)gPrefs.name,gPass)!=noErr) {
- FTPDisconnect(connID);
- CloseStatusWindow();
- ParamText("\pFile not retrieved successfully.","\p","\p","\p");
- NoteAlert(kErrDlg,nil);
- return;
- }
-
- if ((err = FTPViewFile(connID,&newsData,".newsrc"))!=noErr) {
- FTPDisconnect(connID);
- CloseStatusWindow();
- SetCursor(&QDARROW);
- ParamText("\pFile not retrieved successfully.","\p","\p","\p");
- NoteAlert(kErrDlg,nil);
- return;
- }
- CloseStatusWindow();
-
- FTPDisconnect(connID);
-
- NewGroupWindow("\pnewsrc");
- info = (TwindowInfo *)GetWRefCon(window = FrontWindow());
-
- BlockMove("\pnewsrc",info->diskFile,8);
- info->diskVRefNum = 0;
- LDoDraw(false,(ListHandle)info->data);
- current = newsData;
- while (*current)
- ProcessLine(¤t,window);
- LDoDraw(true,(ListHandle)info->data);
- info->changed = false;
- info->saved = false;
-
- if (gPrefs.openWindowsZoomed)
- ToggleZoom(window);
- ShowWindow(window);
- SetPort(window);
- InvalRect(&window->portRect);
- MyDisposPtr(newsData);
- }
-
-
- /* SendToNet sends a user group list to a user's remote account for storage
- as a newsrc file.
- */
-
- void SendToNet(void)
- {
- extern char gPass[];
- extern TPrefRec gPrefs;
- char tmpStr[256];
- char *newsData;
- long newsDataLen;
- long first;
- short offset;
- TWList *current;
- TGroup *theGroup;
- TReadRec *read;
- TwindowInfo *info;
- WindowPtr window;
- unsigned long connID;
-
- window = FrontWindow();
- if (!window || !IsAppWindow(window))
- return;
- info = (TwindowInfo *)GetWRefCon(window);
- if (info->kind != cUserGroup)
- return;
-
- if (!Authenticate())
- return;
-
- StatusWindow("Converting to newsrc format...",-1);
- GiveTime(0);
-
- newsData = (char *)MyNewPtr(kMaxGroupLen);
- if (MyMemErr() != noErr)
- return;
-
- newsDataLen = 0;
- newsData[newsDataLen] = '\0';
-
- /* update read lists */
-
- for (current = info->childList; current != nil; current = current->next)
- MarkReadMsgs((TwindowInfo *) GetWRefCon(current->childWindow));
-
- /* process groups */
-
- for (theGroup = (TGroup *)info->data2; theGroup!=nil; theGroup=theGroup->next) {
- strcat(newsData,theGroup->name);
- strcat(newsData,": ");
-
- first = 1;
- for (read = theGroup->read; read!=nil; read = read->next) {
- if ( (read->firstRead-1 - first) >= 0) {
- sprintf(tmpStr,"%lu-%lu",first,(read->firstRead-1));
- if (read->next)
- strcat(tmpStr,",");
- strcat(newsData,tmpStr);
- }
- first = 1 + read->lastRead;
- }
-
- /* mark read to last message of group */
-
- if (theGroup->lastMess >= first) {
- sprintf(tmpStr,", %lu-%lu",first,theGroup->lastMess);
- if (first==1)
- offset=1;
- else
- offset=0;
- strcat(newsData,tmpStr+offset);
- }
-
- strcat(newsData,CRSTR);
- }
-
- StatusWindow("Establishing FTP Connection...",-1);
- GiveTime(0);
-
- if (FTPConnect(&connID,(char *)gPrefs.host,(char *)gPrefs.name,gPass)!=noErr) {
- FTPDisconnect(connID);
- CloseStatusWindow();
- ParamText("\pFile not sent successfully.","\p","\p","\p");
- NoteAlert(kErrDlg,nil);
- return;
- }
-
- if (FTPPutFile(connID,".newsrc",newsData,strlen(newsData))!=noErr) {
- CloseStatusWindow();
- ParamText("\pFile not sent successfully.","\p","\p","\p");
- NoteAlert(kErrDlg,nil);
- }
-
- FTPDisconnect(connID);
-
- /* newsdata has already been disposed */
- }
-
-
- /* DoSendMsg either posts a message or sends the message through
- electronic mail (SMTP) after converting the appropriate header
- fields, etc...
- */
-
- Boolean DoSendMsg(TwindowInfo *info)
- {
- Handle sendText;
- unsigned short length;
- Boolean result = false;
- long offset;
- char mungeText1[256];
- char mungeText2[256];
- char mungeText3[256];
-
- strcpy(mungeText1,CRSTR);
- strcat(mungeText1,CRSTR);
-
- strcpy(mungeText2,CRSTR);
- strcat(mungeText2,"From");
-
- strcpy(mungeText3,CRSTR);
- strcat(mungeText3,">From");
-
- if (!CheckHeader(info)) {
- ParamText("\pInvalid sender name! Can't send message.","\p","\p","\p");
- StopAlert(kErrDlg,nil);
- return false;
- }
-
- StatusWindow("Sending Message...",-1);
- GiveTime(0);
-
- sendText = (Handle) TEGetText((TEHandle)info->data);
- length = (**((TEHandle)info->data)).teLength;
- if (MyHandToHand(&sendText) != noErr)
- return false;
- MySetHandleSize(sendText,(long)length);
- if (MyMemErr() != noErr)
- return false;
-
- /* remove all "From"s at start of lines */
-
- for (offset = Munger(sendText,0L,mungeText1,2L,nil,0L);
- offset>=0;
- offset = Munger(sendText,offset,mungeText2,5L,mungeText3,6L))
- length++;
-
- length--;
-
- /* convert all "." to "," at start of lines */
-
- if (**sendText=='.')
- **sendText = ',';
-
- strcpy(mungeText1,CRSTR);
- strcat(mungeText1,".");
- strcat(mungeText1,CRSTR);
- strcpy(mungeText2,CRSTR);
- strcat(mungeText2,",");
- strcat(mungeText2,CRSTR);
-
- for (offset = 0; offset>=0; offset = Munger(sendText,offset,mungeText1,3L,mungeText2,3L))
- ;
-
- /* convert CR to CRLF */
-
- for (offset = 0; offset>=0; offset = Munger(sendText,offset,CRSTR,1L,CRLF,2L))
- length++;
-
- length--;
-
- HLock(sendText);
-
- /* send message */
-
- switch (info->kind) {
- case cSendMessage:
- result = SendSMTP((char *)*sendText,length);
- break;
- case cPostMessage:
- result = SendNNTP((char *)*sendText,length);
- break;
- }
- MyDisposHandle(sendText);
-
- CloseStatusWindow();
-
- if (result == false) {
- ParamText("\pMessage not sent successfully.","\p","\p","\p");
- CautionAlert(kErrDlg,nil);
- }
- else
- info->changed = false;
-
- return result;
- }
-
-
-